home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Interactive Reference Guide / C-C++ Interactive Reference Guide.iso / c_ref / csource5 / 363_01 / movem.c < prev    next >
C/C++ Source or Header  |  1991-12-16  |  12KB  |  362 lines

  1. /***********************************************************************
  2.  *
  3.  *      MOVEM - Instructions for 68020 Assembler
  4.  *      Routines for the MOVEM instruction and the REG directive
  5.  *
  6.  *    Function: movem()
  7.  *      Builds MOVEM instructions. The size of the instruction is given by the 
  8.  *      size argument (assumed to be word if not specified). The label argument points to the label 
  9.  *      appearing on the source line containing the MOVEM instruction, if any, 
  10.  *      and the op argument points to the operands of the MOVEM instruction. 
  11.  *      The routine returns an error code in *errorPtr by the standard 
  12.  *      mechanism.
  13.  *      Argument tablePtr is not used. 
  14.  *
  15.  *      reg()
  16.  *      Defines a special register list symbol to be used as an argument for 
  17.  *      the MOVEM instruction. The size argument reflects the size code 
  18.  *      appended to the REG directive, which should be empty. The label 
  19.  *      argument points to the label appearing on the source line containing 
  20.  *      the REG directive (which must be specified), and the op argument 
  21.  *      points to a register list which is the new value of the symbol. The 
  22.  *      routine returns an error code in *errorPtr by the standard mechanism. 
  23.  *      Argument tablePtr is not used. 
  24.  *
  25.  *   Usage: movem(instruction *tablePtr, int size, char *label, char *op,
  26.  *                                                  int *errorPtr)
  27.  *
  28.  *      reg(instruction *tablePtr, int size, char *label, char *op,
  29.  *                                                  int *errorPtr)
  30.  *
  31.  *      Author: Paul McKee
  32.  *      ECE492    North Carolina State University,  12/9/86
  33.  *
  34.  *      Modified A.E. Romer. Version 1.0
  35.  *          17 March 1991:  ANSI functions, braces layout.
  36.  *
  37.  ************************************************************************/
  38.  
  39.  
  40. #include <stdio.h>
  41. #include <ctype.h>
  42. #include "asm.h"
  43.  
  44.  
  45. /* Define bit masks for the legal addressing modes of MOVEM */
  46.  
  47. #define ControlAlt  (AnInd | AnIndDisp | AnIndIndex | AbsShort | AbsLong)
  48. #define DestModes   (ControlAlt | AnIndPre)
  49. #define SourceModes (ControlAlt | AnIndPost | PCDisp | PCIndex)
  50.  
  51.  
  52. extern long loc;
  53. extern char pass2;
  54.  
  55.  
  56. /* Define a couple of useful tests */
  57.  
  58. #define isTerm(c)   (c == ',' || c == '/' || c == '-' || isspace(c) || !c)
  59. #define isRegNum(c) ((c >= '0') && (c <= '7'))
  60.  
  61.  
  62. char *evalList(char *p, unsigned short *listPtr, int *errorPtr)
  63.     {
  64.     char reg1, reg2, r;
  65.     unsigned short regList;
  66.     char symName[SIGCHARS+1];
  67.     char i;
  68.     symbolDef *symbol;
  69.     int status;
  70.  
  71.     regList = 0;
  72.                     /* Check whether the register list is specified
  73.                        explicitly or as a register list symbol */
  74.     if ((p[0] == 'A' || p[0] == 'D') && isRegNum(p[1]) && isTerm(p[2]))
  75.         {
  76.         /* Assume it's explicit */
  77.         while (TRUE)                      /* Loop will be exited via return */
  78.             {
  79.             if ((p[0] == 'A' || p[0] == 'D') && isRegNum(p[1]))
  80.                 {
  81.                 if (p[0] == 'A')
  82.                     reg1 = (char)(8) + p[1] - '0';
  83.                 else
  84.                     reg1 = p[1] - '0';
  85.                 if (p[2] == '/')
  86.                     {
  87.                     /* Set the bit the for a single register */
  88.                     regList |= (1 << reg1);
  89.                     p += 3;
  90.                     }
  91.                 else if (p[2] == '-')
  92.                     if ((p[3] == 'A' || p[3] == 'D') && isRegNum(p[4]) &&
  93.                                                                 isTerm(p[5]))
  94.                         {
  95.                         if (p[5] == '-')
  96.                             {
  97.                             NEWERROR(*errorPtr, SYNTAX);
  98.                             return NULL;
  99.                             }
  100.                         if (p[3] == 'A')
  101.                             reg2 = (char)(8) + p[4] - '0';
  102.                         else
  103.                             reg2 = p[4] - '0';
  104.  
  105.         /* Set all the bits corresponding to registers 
  106.            in the specified range */
  107.                         if (reg1 < reg2)
  108.                             for (r = reg1; r <= reg2; r++)
  109.                                 regList |= (1 << r);
  110.                         else
  111.                             for (r = reg2; r <= reg1; r++)
  112.                                 regList |= (1 << r);
  113.                         if (p[5] != '/')
  114.                             {
  115.         /* End of register list found - return its value */
  116.                             *listPtr = regList;
  117.                             return p+5;
  118.                             }
  119.                         p += 6;
  120.                         }
  121.                     else {
  122.                         /* Invalid character found - return the error */
  123.                         NEWERROR(*errorPtr, SYNTAX);
  124.                         return NULL;
  125.                         }
  126.                 else
  127.                     {
  128.  
  129.                     /* Set the bit the for a single register */
  130.                     regList |= (1 << reg1);
  131.  
  132.                     /* End of register list found - return its value */
  133.                     *listPtr = regList;
  134.                     return p+2;
  135.                     }
  136.                 }
  137.             else
  138.                 {
  139.                 /* Invalid character found - return the error */
  140.  
  141.                 NEWERROR(*errorPtr, SYNTAX);
  142.                 return NULL;
  143.                 }
  144.             }
  145.         }
  146.     else
  147.         {
  148.         /* Try looking in the symbol table for a register list symbol */
  149.  
  150.         if (!isalpha(*p) && *p != '.')
  151.             {
  152.             NEWERROR(*errorPtr, SYNTAX);
  153.             return NULL;
  154.             }
  155.         i = 0;
  156.         /* Collect characters of the symbol's name
  157.            (only SIGCHARS characters are significant) */
  158.         do
  159.             {
  160.             if (i < SIGCHARS)
  161.                 symName[i++] = *p;
  162.             p++;
  163.             } while (isalnum(*p) || *p == '.' || *p == '_' || *p == '$');
  164.  
  165.         /* Check for invalid syntax */
  166.         if (!isspace(*p) && *p != ',' && *p)
  167.             {
  168.             NEWERROR(*errorPtr, SYNTAX);
  169.             return NULL;
  170.             }
  171.         symName[i] = '\0';
  172.  
  173.                         /* Look up the name in the symbol table, resulting
  174.                            in a pointer to the symbol table entry */
  175.         status = OK;
  176.         symbol = lookup(symName, &status);
  177.         if (status < SEVERE)
  178.                             /* The register list symbol must be
  179.                                previously defined in the program */
  180.             if (status == UNDEFINED)
  181.                 {
  182.                 NEWERROR(*errorPtr, status);
  183.                 }
  184.             else if (pass2 && !(symbol->flags & BACKREF))
  185.                 {
  186.                 NEWERROR(*errorPtr, REG_LIST_UNDEF);
  187.                 }
  188.             else
  189.                 {
  190.                 if (symbol->flags & REG_LIST_SYM)
  191.                     *listPtr = (unsigned short)symbol->value;
  192.                 else
  193.                     {
  194.                     NEWERROR(*errorPtr, NOT_REG_LIST);
  195.                     *listPtr = 0x1234;
  196.                     }
  197.                 }
  198.         else
  199.             {
  200.             NEWERROR(*errorPtr, status);
  201.             *listPtr = 0;
  202.             }
  203.         return p;
  204.         }
  205.  
  206.     return NORMAL;
  207.     }
  208.  
  209.  
  210. int movem(instruction *tablePtr, int size, char *label, char *op,
  211.                                                         int *errorPtr)
  212.     {
  213.     char *p;
  214.     int status;
  215.     unsigned short regList, temp, instMask;
  216.     char i;
  217.     opDescriptor memOp;
  218.  
  219.     /* Pick mask according to size code (only .W and .L are valid) */
  220.     if (size == WORD)
  221.         instMask = 0x4880;
  222.     else if (size == LONG)
  223.         instMask = 0x48C0;
  224.     else
  225.         {
  226.         if (size)
  227.             NEWERROR(*errorPtr, INV_SIZE_CODE);
  228.         instMask = 0x4880;
  229.         }
  230.  
  231.     /* Define the label attached to this instruction */
  232.     if (*label)
  233.         create(label, loc, errorPtr);
  234.  
  235.     /* See if the instruction is of the form MOVEM <reg_list>,<ea> */
  236.     status = OK;
  237.  
  238.     /* Parse the register list */
  239.     p = evalList(op, ®List, &status);
  240.     if (status == OK && *p == ',')
  241.         {
  242.         /* Parse the memory address */
  243.  
  244.         p = opParse(++p, &memOp, &status);
  245.         NEWERROR(*errorPtr, status);
  246.         if (status < ERROR)
  247.             {
  248.             /* Check legality of addressing mode */
  249.             if (memOp.mode & DestModes)
  250.                 {
  251.                 /* It's good, now generate the instruction */
  252.                 if (pass2)
  253.                     {
  254.                     output((long int) (instMask | effAddr(&memOp)), WORD);
  255.                     loc += 2;
  256.                                 /* If the addressing mode is address
  257.                                    register indirect with predecrement,
  258.                                    reverse the bits in the register 
  259.                                    list mask */
  260.                     if (memOp.mode == AnIndPre)
  261.                         {
  262.                         temp = regList;
  263.                         regList = 0;
  264.                         for (i = 0; i < 16; i++)
  265.                             {
  266.                             regList <<= 1;
  267.                             regList |= (temp & 1);
  268.                             temp >>= 1;
  269.                             }
  270.                         }
  271.                     output((long) regList, WORD);
  272.                     loc += 2;
  273.                     }
  274.                 else
  275.                     loc += 4;
  276.                 extWords(&memOp, size, errorPtr);
  277.                 return NORMAL;
  278.                 }
  279.             else
  280.                 {
  281.                 NEWERROR(*errorPtr, INV_ADDR_MODE);
  282.                 return NORMAL;
  283.                 }
  284.             }
  285.         }
  286.  
  287.     /* See if the instruction is of the form MOVEM <ea>,<reg_list> */
  288.     status = OK;
  289.  
  290.     /* Parse the effective address */
  291.     p = opParse(op, &memOp, &status);
  292.     NEWERROR(*errorPtr, status);
  293.     if (status < ERROR && *p == ',')
  294.         {
  295.         /* Check the legality of the addressing mode */
  296.         if (memOp.mode & SourceModes)
  297.             {
  298.             /* Parse the register list */
  299.             status = OK;
  300.             p = evalList(++p, ®List, &status);
  301.             if (status == OK)
  302.                 {
  303.                 /* Everything's OK, now build the instruction */
  304.  
  305.                 if (pass2)
  306.                     {
  307.                     output((long) (instMask | 0x0400 | effAddr(&memOp)), WORD);
  308.                     loc += 2;
  309.                     output((long) (regList), WORD);
  310.                     loc += 2;
  311.                     }
  312.                 else
  313.                     loc += 4;
  314.                 extWords(&memOp, size, errorPtr);
  315.                 return NORMAL;
  316.                 }
  317.             }
  318.         else
  319.             {
  320.             NEWERROR(*errorPtr, INV_ADDR_MODE);
  321.             return NORMAL;
  322.             }
  323.         }
  324.  
  325.     /* If the instruction isn't of either form, then return an error */
  326.     NEWERROR(*errorPtr, status);
  327.  
  328.     return NORMAL;
  329.     }
  330.  
  331.  
  332. int reg(instruction *tablePtr, int size, char *label, char *op, int *errorPtr)
  333.     {
  334.     int status;
  335.     symbolDef *symbol;
  336.     unsigned short regList;
  337.  
  338.     if (size)
  339.         NEWERROR(*errorPtr, INV_SIZE_CODE);
  340.     if (!*op)
  341.         {
  342.         NEWERROR(*errorPtr, SYNTAX);
  343.         return NORMAL;
  344.         }
  345.     op = evalList(op, ®List, errorPtr);
  346.     if (*errorPtr < SEVERE)
  347.         if (!*label)
  348.             {
  349.             NEWERROR(*errorPtr, LABEL_REQUIRED);
  350.             }
  351.         else
  352.             {
  353.             status = OK;    
  354.             symbol = create(label, (long) regList, &status);
  355.             NEWERROR(*errorPtr, status);
  356.             if (status < ERROR)
  357.                 symbol->flags |= REG_LIST_SYM;
  358.             }
  359.  
  360.     return NORMAL;
  361.     }
  362.